﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media;

namespace JonThomas.SpaceBounce
{
	public class SpaceShip : Control
	{
		private Image _spriteImage;
		private RotateTransform _rotateTransform;
		private int _imageWidth;
		private int _imageHeight;
		private double _posX = 0;
		private double _posY = 0;
		private int _screenWidth;
		private int _screenHeight;
		private double _turningSpeed;
		/// <summary>How fast the ship accelerates. Calculated from m_speed</summary>
		private double _power;
		private Vector _travelling;
		/// <summary>-1 = counter clock wise, 0 = none, 1 = clock wise</summary>
		private int _rotation = 0;
		private bool _accelerating;
		
		private string _spriteTemplate =
		  "<ControlTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"" +
		  "                  xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">" +
		  "<Image x:Name=\"SpriteImage\">" +
		  "   <Image.RenderTransform>" +
		  "      <RotateTransform x:Name=\"ImageTransform\">" +
		  "      </RotateTransform>" +
		  "   </Image.RenderTransform>" +
		  "</Image>" +
		  "</ControlTemplate>";

		public SpaceShip(Size imageSize, Size screenSize, Point startPosition, double refreshRate)
		{
			_imageWidth = (int)imageSize.Width;
			_imageHeight = (int)imageSize.Height;
			_screenHeight = (int)screenSize.Height;
			_screenWidth = (int)screenSize.Width;
			_accelerating = false;
			_travelling = new Vector(0, 0);
			_turningSpeed = refreshRate;
			_power = refreshRate / 25;
			PosX = startPosition.X;
			PosY = startPosition.Y;

			Template = (ControlTemplate)XamlReader.Load(_spriteTemplate);
			ApplyTemplate();
		}

		public override void OnApplyTemplate()
		{
			_spriteImage = (Image)GetTemplateChild("SpriteImage");
			_rotateTransform = (RotateTransform)GetTemplateChild("ImageTransform");

			_rotateTransform.CenterX = _imageWidth / 2;
			_rotateTransform.CenterY = _imageHeight / 2;
		}

		public void SetImage(string resource)
		{
			Uri uri = new Uri(resource, UriKind.Relative);
			ImageSource imgSrc = new System.Windows.Media.Imaging.BitmapImage(uri);
			_spriteImage.Source = imgSrc;
		}

		internal double AngleDegrees
		{
			get { return Math.Abs(_rotateTransform.Angle % 360); }
		}

		internal double AngleRadians
		{
			get { return Math.PI * _rotateTransform.Angle / 180; }
		}

		internal Vector Vector
		{
			get { return _travelling; }
		}

		public void Move()
		{
			_travelling += new Vector(0.1, Math.PI);

			Rotate(_rotation);

			Bounce();

			if (_accelerating)
			{
				_travelling += new Vector(_power, AngleRadians);
			}

			PosX += _travelling.X;
			PosY += _travelling.Y;
		}

		private void Bounce()
		{
			if (_posX <= 0 || _posX + _imageWidth >= _screenWidth)
			{
				_travelling = new Vector(_travelling.Speed - (_power*0.4), _travelling.Angle * -1);
			}
			else if (_posY <= 0 || _posY + _imageHeight >= _screenHeight)
			{
				_travelling = new Vector(_travelling.Speed - (_power * 0.4), Math.PI - _travelling.Angle);
			}
		}

		private void Rotate(int direction)
		{
			if (direction != 0)
			{
				_rotateTransform.Angle += direction * _turningSpeed;
				_rotateTransform.Transform(new Point(32, 24));
			}
		}

		private void ChangeDirection()
		{
			Random rand = new Random();

			double xi = rand.Next(1, 100);
			double yi = rand.Next(1, 100);
			xi *= 0.01;
			yi *= 0.01;
			int n1 = rand.Next(0, 2);
			int n2 = rand.Next(0, 2);
			if (n1 == 0)
				xi *= -1;
			if (n2 == 0)
				yi *= -1;
			_travelling = new Vector(new Point(xi, yi));
		}

		#region Public interface

		public double PosX
		{
			get { return _posX; }
			private set
			{
				_posX = value;
				if (_posX < 0) 
					_posX = 0;
				else if (_posX + _imageWidth > _screenWidth) 
					_posX = _screenWidth - _imageWidth;
				
				this.SetValue(Canvas.LeftProperty, _posX);
			}
		}

		public double PosY
		{
			get { return _posY; }
			private set
			{
				_posY = value;
				if (_posY < 0) 
					_posY = 0;
				else if (_posY + _imageHeight > _screenHeight) 
					_posY = _screenHeight - _imageHeight;
				
				this.SetValue(Canvas.TopProperty, _posY);
			}
		}

		public void StartAcceleration()
		{
			_accelerating = true;
		}

		public void StopAcceleration()
		{
			_accelerating = false;
		}

		public void StartLeftTurn()
		{
			_rotation = -1;
		}

		public void StartRightTurn()
		{
			_rotation = 1;
		}

		public void StopTurning()
		{
			_rotation = 0;
		}
		#endregion
	}
}